<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>微信授权跳转页面</title>
    <!-- 可选：通过 meta 配置覆盖，便于不同环境注入，无需改代码 -->
    <!-- <meta name="wx-appid" content="YOUR_APPID_HERE" /> -->
    <!-- <meta name="wx-scope" content="snsapi_base" /> -->
    <!-- <meta name="wx-server-url" content="https://your.domain" /> -->
    <style>
      :root {
        --primary-color: #07c160;
        --primary-hover: #06ae56;
        --success-bg: #e8f5e8;
        --success-text: #2e7d32;
        --error-bg: #ffebee;
        --error-text: #c62828;
        --loading-bg: #e3f2fd;
        --loading-text: #1976d2;
        --info-bg: #fff8e1;
        --info-text: #f57f17;
      }

      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
      }

      body {
        font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
        line-height: 1.6;
        color: #333;
        background-color: #f5f5f5;
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 20px;
      }

      .container {
        background: white;
        padding: 30px;
        border-radius: 12px;
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
        text-align: center;
        max-width: 500px;
        width: 100%;
        transition: all 0.3s ease;
      }

      h1 {
        color: #333;
        margin-bottom: 20px;
        font-size: 24px;
      }

      .status {
        margin: 20px 0;
        padding: 15px;
        border-radius: 8px;
        font-weight: 500;
        transition: all 0.3s ease;
      }

      .loading {
        background: var(--loading-bg);
        color: var(--loading-text);
      }

      .success {
        background: var(--success-bg);
        color: var(--success-text);
      }

      .error {
        background: var(--error-bg);
        color: var(--error-text);
      }

      .info {
        background: var(--info-bg);
        color: var(--info-text);
      }

      .openid-display {
        background: #f5f5f5;
        padding: 15px;
        border-radius: 8px;
        margin: 15px 0;
        word-break: break-all;
        font-family: "Courier New", monospace;
        font-size: 14px;
        text-align: left;
        border: 1px solid #eee;
      }

      .user-info {
        text-align: left;
        margin: 20px 0;
        padding: 15px;
        background: #f9f9f9;
        border-radius: 8px;
      }

      .user-info-item {
        margin: 8px 0;
        display: flex;
      }

      .user-info-label {
        font-weight: bold;
        width: 80px;
        flex-shrink: 0;
      }

      button {
        background: var(--primary-color);
        color: white;
        border: none;
        padding: 12px 24px;
        border-radius: 6px;
        cursor: pointer;
        font-size: 16px;
        font-weight: 500;
        transition: all 0.2s ease;
        margin: 5px;
        min-width: 120px;
      }

      button:hover {
        background: var(--primary-hover);
        transform: translateY(-2px);
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
      }

      button:active {
        transform: translateY(0);
      }

      button.secondary {
        background: #6c757d;
      }

      button.secondary:hover {
        background: #5a6268;
      }

      .spinner {
        border: 3px solid rgba(0, 0, 0, 0.1);
        border-top: 3px solid var(--loading-text);
        border-radius: 50%;
        width: 24px;
        height: 24px;
        animation: spin 1s linear infinite;
        display: inline-block;
        margin-right: 10px;
        vertical-align: middle;
      }

      @keyframes spin {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }

      .hidden {
        display: none !important;
      }

      .retry-info {
        font-size: 14px;
        color: #666;
        margin-top: 10px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>微信授权页面</h1>
      <div id="status" class="status loading" role="status" aria-live="polite">
        <span class="spinner"></span>
        正在处理微信授权...
      </div>

      <div id="result" class="hidden">
        <h3>授权成功</h3>
        <p>openid已成功获取！</p>
        <div class="openid-display" id="openidDisplay"></div>

        <div class="user-info hidden" id="userInfoSection">
          <h4>用户信息</h4>
          <div class="user-info-item">
            <span class="user-info-label">昵称:</span>
            <span id="userNickname"></span>
          </div>
          <div class="user-info-item">
            <span class="user-info-label">性别:</span>
            <span id="userGender"></span>
          </div>
          <div class="user-info-item">
            <span class="user-info-label">地区:</span>
            <span id="userLocation"></span>
          </div>
        </div>

        <button onclick="getUserInfo()">获取用户信息</button>
        <button class="secondary" onclick="copyOpenId()">复制OpenID</button>
      </div>

      <div id="error" class="hidden">
        <h3>授权失败</h3>
        <p id="errorMessage"></p>
        <div class="retry-info">请检查配置或网络连接后重试</div>
        <button onclick="retryAuth()">重新授权</button>
        <button class="secondary" onclick="manualAuth()">手动授权</button>
      </div>
    </div>

    <script>
      // 配置信息
      function getMeta(name) {
        const el = document.querySelector(`meta[name="${name}"]`);
        return el ? el.getAttribute("content") : undefined;
      }

      const CONFIG = (function () {
        const metaAppid = getMeta("wx-appid");
        const metaScope = getMeta("wx-scope");
        const metaServer = getMeta("wx-server-url");
        const winConf = window.WECHAT_CONFIG || {};

        return {
          appid: "wx1252cf1f26c7faee", // 默认示例，可被覆盖
          scope:  "snsapi_base",
          serverUrl:   window.location.origin,
        };
      })();

      // 检查URL中的code参数
      const urlParams = new URLSearchParams(window.location.search);
      const code = urlParams.get("code");
      const state = urlParams.get("state");

      // 页面加载完成后的初始化
      document.addEventListener("DOMContentLoaded", function () {
        console.log("页面加载完成");
        console.log("当前URL:", window.location.href);
        console.log("URL参数:", Object.fromEntries(urlParams.entries()));

        // 检查是否配置了appid
        if (!CONFIG.appid || CONFIG.appid === "YOUR_APPID_HERE") {
          showError("请先配置您的微信公众号appid");
          return;
        }

        // 根据是否有code参数决定流程
        if (!code) {
          // 未获取到code，发起授权请求
          console.log("未检测到code参数，发起微信授权请求");
          initiateAuth();
        } else {
          // 使用code换取openid
          console.log("检测到code参数:", code);
          showStatus("正在获取用户信息...", "loading");
          getOpenId(code);
        }
      });

      // 发起微信授权
      function initiateAuth() {
        showStatus("正在跳转到微信授权页面...", "loading");
        setLoading(true);

        // 构造回调URL，去除可能存在的参数
        const redirectUri = window.location.href.split("?")[0]
        // 授权后重定向的回调链接地址， 请使用 urlEncode 对链接进行处理
        const encodedRedirectUri = encodeURIComponent(redirectUri);
        // 构造微信授权URL
        const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${CONFIG.appid}&redirect_uri=${encodedRedirectUri}&response_type=code&scope=${CONFIG.scope}&state=abc#wechat_redirect`;
        // 3秒后跳转到微信授权页面
        setTimeout(() => {
          window.location.href = authUrl;
        }, 80);
      }

      // 使用code换取openid
      async function getOpenId(code) {
        try {
          showStatus("正在获取openid...", "loading");
          setLoading(true);

          // 调用后端API获取openid
          const response = await fetchWithTimeout(
            `/api/auth/openid?code=${encodeURIComponent(code)}`,
            {
              method: "GET",
              headers: { "Content-Type": "application/json" },
            },
            10000
          );

          const data = await parseJsonSafely(response);
          if (!response.ok) {
            const msg = (data && (data.error || data.message)) || response.statusText;
            throw new Error(`服务异常 (${response.status}): ${msg}`);
          }
          console.log("获取openid结果:", data);

          if (data.openid) {
            showSuccess(data);
          } else {
            throw new Error(data.error || "获取openid失败");
          }
        } catch (error) {
          console.error("获取openid失败:", error);
          showError(`获取openid失败: ${error.message}`);
        }
        finally {
          setLoading(false);
        }
      }

      // 获取用户详细信息
      async function getUserInfo() {
        try {
          // 从页面中获取之前保存的access_token和openid
          const accessTokenElement = document.getElementById("accessToken");
          const openidElement = document.getElementById("openidDisplay");

          if (!accessTokenElement || !openidElement) {
            throw new Error("缺少必要的认证信息");
          }

          const access_token = accessTokenElement.textContent;
          const openid = openidElement.textContent;

          showStatus("正在获取用户信息...", "loading");
          setLoading(true);

          // 调用后端API获取用户信息
          const response = await fetchWithTimeout(
            `/api/auth/userinfo?access_token=${encodeURIComponent(
              access_token
            )}&openid=${encodeURIComponent(openid)}`,
            { method: "GET", headers: { "Content-Type": "application/json" } },
            10000
          );

          const data = await parseJsonSafely(response);
          if (!response.ok) {
            const msg = (data && (data.error || data.message)) || response.statusText;
            throw new Error(`服务异常 (${response.status}): ${msg}`);
          }
          console.log("获取用户信息结果:", data);

          if (data.userInfo) {
            showUserInfo(data.userInfo);
          } else {
            throw new Error(data.error || "获取用户信息失败");
          }
        } catch (error) {
          console.error("获取用户信息失败:", error);
          showError(`获取用户信息失败: ${error.message}`);
        }
        finally {
          setLoading(false);
        }
      }

      // 显示授权成功结果
      function showSuccess(data) {
        document.getElementById("status").classList.add("hidden");
        document.getElementById("result").classList.remove("hidden");
        document.getElementById("error").classList.add("hidden");

        // 显示openid
        document.getElementById("openidDisplay").textContent = data.openid;

        // 保存access_token到页面中以便后续使用
        const accessTokenElement = document.createElement("div");
        accessTokenElement.id = "accessToken";
        accessTokenElement.style.display = "none";
        accessTokenElement.textContent = data.access_token;
        document.body.appendChild(accessTokenElement);

        showStatus("授权成功！", "success");
      }

      // 显示用户信息
      function showUserInfo(userInfo) {
        const userInfoSection = document.getElementById("userInfoSection");
        userInfoSection.classList.remove("hidden");

        // 显示用户信息
        document.getElementById("userNickname").textContent =
          userInfo.nickname || "未设置";

        // 性别转换
        const genderMap = { 0: "未知", 1: "男", 2: "女" };
        document.getElementById("userGender").textContent =
          genderMap[userInfo.sex] || "未知";

        // 地区信息
        const location = [userInfo.country, userInfo.province, userInfo.city]
          .filter((item) => item)
          .join(" - ");
        document.getElementById("userLocation").textContent =
          location || "未知";

        showStatus("用户信息获取成功！", "success");
      }

      // 显示错误信息
      function showError(message) {
        document.getElementById("status").classList.add("hidden");
        document.getElementById("result").classList.add("hidden");
        document.getElementById("error").classList.remove("hidden");

        document.getElementById("errorMessage").textContent = message;
        showStatus("授权失败", "error");
      }

      // 显示状态信息
      function showStatus(message, type) {
        const statusDiv = document.getElementById("status");
        statusDiv.classList.remove(
          "loading",
          "success",
          "error",
          "info",
          "hidden"
        );
        statusDiv.classList.add(type);

        // 根据状态类型设置内容
        if (type === "loading") {
          statusDiv.innerHTML = `<span class="spinner"></span>${message}`;
        } else {
          statusDiv.textContent = message;
        }

        statusDiv.classList.remove("hidden");
      }

      // 禁用按钮，避免重复触发
      function setLoading(isLoading) {
        const buttons = document.querySelectorAll("button");
        buttons.forEach((btn) => {
          btn.disabled = isLoading;
          if (isLoading) {
            btn.setAttribute("aria-disabled", "true");
          } else {
            btn.removeAttribute("aria-disabled");
          }
        });
      }

      // 带超时与中止控制的请求
      async function fetchWithTimeout(url, options = {}, timeoutMs = 10000) {
        const controller = new AbortController();
        const id = setTimeout(() => controller.abort(), timeoutMs);
        try {
          const res = await fetch(url, { ...options, signal: controller.signal });
          return res;
        } catch (err) {
          if (err.name === "AbortError") {
            throw new Error("请求超时，请稍后重试");
          }
          throw err;
        } finally {
          clearTimeout(id);
        }
      }

      // 安全解析 JSON，失败时返回文本
      async function parseJsonSafely(response) {
        try {
          return await response.json();
        } catch (_) {
          try {
            const text = await response.text();
            return { message: text };
          } catch (e) {
            return undefined;
          }
        }
      }

      // 重新授权
      function retryAuth() {
        showStatus("正在重新发起授权...", "loading");
        setTimeout(() => {
          initiateAuth();
        }, 1000);
      }

      // 手动授权（用户可以手动输入code）
      function manualAuth() {
        const code = prompt("请输入微信授权返回的code参数：");
        if (code) {
          showStatus("正在处理手动输入的code...", "loading");
          getOpenId(code);
        }
      }

      // 复制OpenID到剪贴板
      function copyOpenId() {
        const openid = document.getElementById("openidDisplay").textContent;
        if (!openid) {
          showError("没有可复制的OpenID");
          return;
        }

        navigator.clipboard
          .writeText(openid)
          .then(() => {
            // 显示临时成功消息
            const originalText = document.getElementById("status").textContent;
            showStatus("OpenID已复制到剪贴板", "success");
            setTimeout(() => {
              showStatus(originalText, "success");
            }, 2000);
          })
          .catch((err) => {
            console.error("复制失败:", err);
            showError("复制失败，请手动选择复制");
          });
      }
    </script>
  </body>
</html>
